Release 10.1A: OpenEdge Development:
Progress 4GL Handbook
Repositioning a query
Often you need to reposition a query other than to the first, last, next, or previous row. You might need to jump to a row based on data the user entered or return to a row that you previously saved off. Or you might want to jump forward or backward a specific number of rows to simulate paging through the query. You can do all these things with the
REPOSITIONstatement, which has this syntax:
The
query-namein this case is not an expression. It can only be an unquoted query name, not a variable.If you specify the
TO ROWoption followed by an integer expression, the query repositions to that sequential position within the results list. If you have previously saved off that position using theCURRENT-RESULT-ROWfunction, you can use the value that function returned as the value in theTO ROWphrase to reposition to that row.If you use the
FORWARDSorBACKWARDSphrase, you can jump forward or backward any number of rows, specified by theninteger expression. You can use theFORWARDorBACKWARDkeywords instead ofFORWARDSorBACKWARDS.The last of the
REPOSITIONoptions requires an explanation of a Progress data construct you haven’t seen before.Using a RowID to identify a record
Every record in every table of a database has a unique row identifier. (Technically, the row identifier is only unique within a single storage area of a database. Since an entire database table must be allocated to a single storage area, this effectively makes the identifier unique at least within that table. A discussion of database constructs such as storage areas is beyond the scope of this book.)
The identifier is called a RowID. There is both a
ROWIDdata type that allows you to store a row identifier in a procedure variable and aROWIDfunction to return the identifier of a record from its record buffer.Generally, you should consider a RowID to be a special data type without being concerned about its storage format. The RowID is (among other things) designed to be valid, not just for the OpenEdge database, but for all the different databases you can access from the 4GL using OpenEdge DataServers, which provide access from the 4GL to database types such as Oracle and Microsoft SQLServer.
In fact, you can’t display a RowID directly in a Progress 4GL procedure. If you try to, you get an error. You can see a RowID by converting it to a
CHARACTERtype using theSTRINGfunction. For instance, here is a procedure that shows you the RowIDs of the rows that satisfy the sample query you’ve been working with:
Figure 10–5 shows the result.
Figure 10–5: Result of RowID example
![]()
The RowID is displayed as a hexadecimal value. The values you would see in your own copy of the Sports2000 database might be different from these, and certainly they would be different if you modified the data, dumped it, and reloaded it into the database, because the RowID reflects the actual storage location of the data for the record, and this is not in any way predictable or necessarily repeatable. You should never count on a RowID as a permanent identifier for a record. However, you can use a RowID if you need to relocate a record you have previously retrieved within a procedure and whose RowID you saved off. This is what the
TOROWIDphrase in theREPOSITIONstatement is for.Even in this case, you must be aware that in the event of a record deletion, it is possible that a new record could be created that has the same RowID as the record that was deleted. So, even within a single session a RowID is not an absolutely reliable pointer to a record. In addition, RowIDs are unique only within a single database storage area. Therefore, the same RowID might occur for records in different tables that happen to be in different storage areas.
With these conditions in mind, you can use the
TO ROWIDphrase to reposition to a record in a query. Note that the RowID is for a particular database record, not an entire query row, so you need to save off the RowID of the record buffer, not of the query name, to reuse it. And in the case of a query with a join between tables, you need to save the RowID of each record buffer in order to reposition to it later and restore each of the records in the join.The
NO-ERRORoption in this phrase lets you suppress an error message if the RowID turns out to be invalid for any reason. You could then use theAVAILABLEfunction or theERROR-STATUShandle (see Chapter 17 "Managing Transactions") to determine whether the query was successfully repositioned.There is another similar identifier in Progress called a
RECID. This identifier was used in earlier versions of Progress to identify records in the same way as RowIDs do now. TheRECIDis essentially an integer identifier for a record, though it has its own data type. It is still supported but for several reasons (including, but not limited to, portability of code between database types that you can access with DataServers), it is strongly recommended that you use only the RowID form in new application code. The Progress 4GL continues to supportRECIDs mainly for backward compatibility with older applications that still use them.Positioning details with the REPOSITION statement
So if you execute a
REPOSITIONstatement that repositionsTO ROW 5orFORWARDS 10orTO ROWID rRow, then your procedure is positioned to that row so that you can display it or otherwise use it, right? Well, not exactly. When you use theREPOSITIONstatement, Progress positions the query in between records, so that you then have to execute aGET NEXTorGET PREVstatement to position on a row so that you can actually use it. Here are some of the specifics:
- When you execute a
REPOSITIONstatement that uses theTO ROWIDorTO ROWphrase, the query is positioned before the record requested. You then need to execute aGET NEXTstatement to make the row you want available.- When you execute a
REPOSITIONquery-nameBACKWARDSstatement, the query is positioned between records, and you need to execute aGET NEXTstatement to make the row you intend available. For example, if the query is positioned to row 6 of a query results list and you execute aREPOSITIONquery-nameBACKWARDS 2, then the query is positioned effectively between results list rows 3 and 4, and aGET NEXTstatement makes row 4 available. AGET PREVstatement makes row 3 available.- When you execute a
REPOSITIONstatement with theFORWARDSphrase, you are actually positioned beyond the record you might expect. For example, if you are on row 6 and issue a statement withFORWARDS 2, then the query is positioned between row 8 and row 9, and you need to then execute aGET PREVstatement to make row 8 available or aGET NEXTstatement to make row 9 available.Note as well that there is only one way for Progress to know which row is five rows ahead of the current row, or five rows behind it, or the fifth row of the result set, and that is to walk through the query row by row until it gets to the one you want. If the row in question has already been retrieved and is in the results list, then Progress can reposition to the row you want very quickly using the results list. Therefore, the
REPOSITIONstatement with any of the optionsTO ROW,FORWARDS, orBACKWARDSmaintains the integrity of the results list and the functions that use it. TheREPOSITION TO ROWIDstatement also maintains the integrity of the list if the row you want has already been retrieved and the results list has not been flushed since you retrieved it, because Progress can scan the results list to locate the RowID.
|
Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095 |